package de.tmahr.android.animation;

import de.tmahr.android.R;
import de.tmahr.android.logger.LogCatLogger;
import de.tmahr.android.logger.Logger;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

/**
 * Diese spezialisierte SurfaceView führt eine Animation in einem separaten
 * Thread aus. Dazu erhält die Klasse eine Instanz der Klasse @see
 * de.tmahr.android.RenderView.Animation und ruft für dieses die Methode @see
 * de.tmahr.android.RenderView.Animation.render auf. Eine SurfaceView bietet
 * einen Zugriff auf den Speicherbereich (Surface), der von Android für die
 * Bildschirmdarstellung verwendet wird.
 */
public class RenderView extends SurfaceView implements Runnable
{
	public interface Animation
	{
		void render(Canvas canvas);

		void setBackgroundColor(int c);
	}

	private Animation animation;

	/**
	 * Da wir in einem eigenen Thread auf Surface zugreifen wollen, benötigen
	 * wir einen SurfaceHolder, der den Zugriff auf den Speicher regelt.
	 */
	private SurfaceHolder holder;
	private Thread thread = null;
	private volatile boolean running = false;
	private Logger logger = new LogCatLogger(RenderView.class.getSimpleName());
	private int backgroundColor;
	private String name = "";

	public RenderView(Context c, AttributeSet as)
	{
		super(c, as);

		// Wir holen uns über SurfaceView.getHolder() Zugriff auf den
		// Grafikspeicher.
		holder = getHolder();

		// Wir lesen die im XML-Layout definierten Parameter aus:
		parseXmlLayoutParameter(as);
	}

	/**
	 * Liest die im XML-Layout definierten Parameter aus.
	 * 
	 * @param as
	 */
	private void parseXmlLayoutParameter(AttributeSet as)
	{
		android.content.res.TypedArray ta = getContext()
				.obtainStyledAttributes(as, R.styleable.RenderView);

		String s = ta.getString(R.styleable.RenderView_android_text);
		if (s != null)
		{
			name = s;
			logger.log("name: " + s);
		}

		backgroundColor = ta.getColor(R.styleable.RenderView_hintergrundFarbe,
				Color.BLACK);
		logger.log(name+".hintergrundFarbe=" + backgroundColor);

		int rotFilter = ta.getInt(R.styleable.RenderView_rotFilter, 0);
		logger.log("rotFilter : " + rotFilter);

		ta.recycle();
	}

	/**
	 * Setzt den Logger.
	 * 
	 * @param logger
	 */
	public void setLogger(Logger logger)
	{
		this.logger = logger;
	}

	/**
	 * Setzt die zu animierende Welt.
	 * 
	 * @param w
	 */
	public void setSimulation(Animation sim)
	{
		animation = sim;
		animation.setBackgroundColor(backgroundColor);
	}

	/**
	 * Beginne die Animation.
	 */
	public void resume()
	{
		running = true;
		thread = new Thread(this);
		thread.start();
		logger.log("Thread gestartet");
	}

	/**
	 * Halte die Animation an.
	 */
	public void pause()
	{
		running = false;
		while (true)
		{
			try
			{
				thread.join();
				logger.log("Thread gestoppt");
				break;
			}
			catch (InterruptedException e)
			{
			}
		}
	}

	@Override
	public void run()
	{
		while (running)
		{
			if (!holder.getSurface().isValid())
			{
				continue;
			}

			/*
			 * Surface für Schreibzugriff sperren
			 */
			Canvas c = holder.lockCanvas();

			animation.render(c);

			/*
			 * Surface wieder freigeben
			 */
			holder.unlockCanvasAndPost(c);
		}
	}
}
